package arts.spbu.testswing;

import java.awt.*;
import java.awt.event.*;
import java.awt.Color;
import javax.swing.*;
import javax.swing.event.*;

import layout.TableLayout;

import java.io.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.Highlighter;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.BadLocationException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.regex.*;
import java.lang.*;
import java.util.Collections;

/**
 * Created with IntelliJ IDEA.
 * User: pev67021
 * Date: 29.10.12
 * Time: 8:50
 */

public class FormWin {
    private JMenuItem helpMenu;
    private JMenuItem fileMenu;
    private JMenuItem dbMenu;
    private JMenuItem optMenu;
    private JFrame jfrm;
    private JTextField jtxtuser;
    private JTextArea jtxt;
    private JFrame dbWin;
    private JLabel dbModeLabel;
    private Highlighter highlighter;
    private DefaultHighlighter.DefaultHighlightPainter painter;
    private DefaultHighlighter.DefaultHighlightPainter painter_sel;
    private JList<MatchEntry> reglist;
    private DefaultListModel<MatchEntry> listModel;
    private Highlighter.Highlight curhl;
    private JLabel errlabel;
    private JButton jbtnReg;
    private Trie trie;
    private DBtest db;
    private DataModel annTableModel;
    private boolean isRegMode;
    private String filename;
    private boolean batchInsertMode;

    private final static Integer MaxEntryNumber = 100;

    // Главная форма
    public FormWin() {

        isRegMode = true;
        filename = "";
        batchInsertMode = false;
        jfrm = new JFrame("Текстовый поиск");
        double size[][] =
                {{20, TableLayout.PREFERRED, 20, TableLayout.FILL, 20},
                        {20, TableLayout.PREFERRED, 20, TableLayout.PREFERRED, 30, TableLayout.PREFERRED, 20, TableLayout.FILL, 20, 20, 20}};

        jfrm.setLayout(new TableLayout(size));
        jfrm.setSize(800, 600);
        jfrm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jfrm.setLocationRelativeTo(null);
        jfrm.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                db.disconnect();
                System.exit(0);
            }
        });

        ImageIcon img = new ImageIcon("loupe.png");
        jfrm.setIconImage(img.getImage());

        errlabel = new JLabel();
        errlabel.setForeground(Color.red);

        dbModeLabel = new JLabel("БД: вставка конкатенацией");

        jtxtuser = new JTextField();

        DocumentListener docListener = new DocumentListener() {
            public void changedUpdate(DocumentEvent documentEvent) {
                checkIt(documentEvent);
            }

            public void insertUpdate(DocumentEvent documentEvent) {
                checkIt(documentEvent);
            }

            public void removeUpdate(DocumentEvent documentEvent) {
                checkIt(documentEvent);
            }

            private void checkIt(DocumentEvent documentEvent) {
                String err = "";
                int doclen = documentEvent.getDocument().getLength();
                try {
                    RegClass myReg = new RegClass(documentEvent.getDocument().getText(0, doclen));
                    err = myReg.getError();
                } catch (BadLocationException e) {
                    JOptionPane.showMessageDialog(jfrm, e, "Ошибка", JOptionPane.ERROR_MESSAGE);
                }

                if (!err.equals("")) {
                    errlabel.setText("Неверное выражение!");
                    jbtnReg.setEnabled(false);
                    return;
                }

                errlabel.setText("");
                jbtnReg.setEnabled(true);
            }
        };

        jtxtuser.getDocument().addDocumentListener(docListener);

        jtxt = new JTextArea();
        jtxt = new JTextArea();
        jtxt.setEditable(false);  // Отключаем возможность редактирования TextArea пользователем
        jtxt.setFont(new Font("Courier", Font.ITALIC, 16));
        jtxt.setLineWrap(true);
        jtxt.setWrapStyleWord(true);

        // Соединение с БД, создание таблиц, если они еще не определены
        db = new DBtest();

        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.lightGray);
        painter_sel = new DefaultHighlighter.DefaultHighlightPainter(Color.orange);

        jbtnReg = new JButton("Показать!");
        jbtnReg.setEnabled(true);
        jbtnReg.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {

                String textPattern = jtxtuser.getText();
                if (!isRegMode)
                    textPattern = wordsToRegExp(jtxtuser.getText());

                if (batchInsertMode)
                    execRegBatch(jtxt, textPattern);
                else
                    execReg(jtxt, textPattern);
            }
        });

        JScrollPane scrollPane = new JScrollPane(jtxt);
        JPanel content = new JPanel();
        content.setLayout(new BorderLayout());
        content.add(scrollPane, BorderLayout.CENTER);

        highlighter = jtxt.getHighlighter();

        listModel = new DefaultListModel<>();
        reglist = new JList<>(listModel);
        reglist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        reglist.setCellRenderer(new RegCellRenderer());

        reglist.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                paintTxtArea();
            }
        });

        JScrollPane listscroll = new JScrollPane(reglist);
        JPanel listpanel = new JPanel();
        listpanel.setLayout(new BorderLayout());
        listpanel.add(listscroll, BorderLayout.CENTER);

        createFileMenu();
        createDBMenu();
        createHelpMenu();
        createOptionsMenu();

        JMenuBar menuBar = new JMenuBar();
        jfrm.setJMenuBar(menuBar);
        menuBar.add(fileMenu);
        menuBar.add(dbMenu);
        menuBar.add(optMenu);
        menuBar.add(helpMenu);

        annTableModel = new DataModel();
        JTable annTable = new JTable(annTableModel);
        annTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
        annTable.setCellSelectionEnabled(true);
        //annTable.getColumnModel().getColumn(6).setPreferredWidth(50);

        dbWin = new JFrame("База аннотаций");
        dbWin.setSize(750, 500);
        dbWin.setLocationRelativeTo(null);
        dbWin.setLayout(new BorderLayout());
        ImageIcon imgDB = new ImageIcon("db.png");
        dbWin.setIconImage(imgDB.getImage());
        dbWin.setVisible(false);

        dbWin.getContentPane().add(new JScrollPane(annTable));

        JRadioButton jbtnRadioRegs = new JRadioButton("Поиск регулярных выражений", true);
        JRadioButton jbtnRadioWrds = new JRadioButton("Поиск словоформ", false);

        jbtnRadioRegs.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JRadioButton rb = (JRadioButton) ae.getSource();
                isRegMode = rb.isSelected();
            }
        });

        jbtnRadioWrds.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JRadioButton rb = (JRadioButton) ae.getSource();
                isRegMode = (!rb.isSelected());

            }
        });
        ButtonGroup titlebtnGroup = new ButtonGroup();
        titlebtnGroup.add(jbtnRadioRegs);
        titlebtnGroup.add(jbtnRadioWrds);

        jfrm.add(jtxtuser, "1, 3");
        jfrm.add(content, "3, 3, 3, 9");
        jfrm.add(jbtnReg, "1, 5");
        jfrm.add(listpanel, "1, 7");
        jfrm.add(errlabel, "1, 4");
        jfrm.add(jbtnRadioRegs, "1, 1");
        jfrm.add(jbtnRadioWrds, "3, 1");
        jfrm.add(dbModeLabel, "1, 9");
        jfrm.setVisible(true);

        System.out.println("Concatenation mode");
    }

    private void paintTxtArea() {
        MatchEntry pair = reglist.getSelectedValue();
        if (pair == null)
            return;
        jtxt.setCaretPosition(pair.getBeg());
        try {
            highlighter = jtxt.getHighlighter();

            if (curhl != null) {
                if (curhl.getStartOffset() == pair.getBeg() && curhl.getEndOffset() == pair.getEnd())
                    return;
                highlighter.addHighlight(curhl.getStartOffset(), curhl.getEndOffset(), painter);
                highlighter.removeHighlight(curhl);
            }

            Highlighter.Highlight[] hls = highlighter.getHighlights();
            for (Highlighter.Highlight hl : hls) {
                if (hl.getStartOffset() == pair.getBeg() && hl.getEndOffset() == pair.getEnd()) {
                    highlighter.removeHighlight(hl);
                    curhl = (Highlighter.Highlight) highlighter.addHighlight(pair.getBeg(), pair.getEnd(), painter_sel);
                    return;
                }

                if (hl.getStartOffset() < pair.getBeg() && hl.getEndOffset() > pair.getBeg()
                        || hl.getStartOffset() < pair.getEnd() && hl.getEndOffset() > pair.getEnd()) {
                    if (hl.getStartOffset() < pair.getBeg())
                        highlighter.addHighlight(hl.getStartOffset(), pair.getBeg(), painter);
                    if (hl.getEndOffset() > pair.getEnd())
                        highlighter.addHighlight(pair.getEnd(), hl.getEndOffset(), painter);
                    highlighter.removeHighlight(hl);
                }

                if (hl.getStartOffset() >= pair.getBeg() && hl.getEndOffset() <= pair.getEnd()) {
                    highlighter.removeHighlight(hl);
                }
            }
            curhl = (Highlighter.Highlight) highlighter.addHighlight(pair.getBeg(), pair.getEnd(), painter_sel);

        } catch (BadLocationException ex) {
            JOptionPane.showMessageDialog(jfrm, ex);
        }
    }

    // Преобразование строки из выдачи mystem в список типа <словоформа, лемма_1, лемма_2, ... >
    private java.util.List<String> wordMatches(String text) {
        String regstr = "[-а-яА-яa-zA-Z0-9Ёё]+\\{[-а-яА-яa-zA-Z0-9Ёё]+\\?{0,2}";
        String lemsplitter = "(?:\\{|\\}|\\|(?=[-а-яА-Яa-zA-Z0-9Ёё]))";

        Pattern pat;
        Matcher mat;

        java.util.List<String> entries = null;
        try {
            pat = Pattern.compile(regstr);
            mat = pat.matcher(text);

            if (!mat.find(0))
                return null;
            entries = Arrays.asList(text.split(lemsplitter));

        } catch (java.util.regex.PatternSyntaxException ex) {
            JOptionPane.showMessageDialog(jfrm, ex);
        }
        return entries;
    }

    // Преобразование поискового запроса (слова) в регулярное выражение для последующего поиска в тексте
    private String wordsToRegExp(String pattern) {
        if (trie == null)
            return "";
        if (!trie.find(pattern.toLowerCase()) && !trie.findLemma(pattern.toLowerCase()))
            return "";
        String[] lems = trie.getLemmas(pattern);
        ArrayList<String> search_pats = new ArrayList<>();

        if (lems != null) {
            for (int i = 1; i < lems.length; i++) {
                if (trie.getForms(lems[i]) != null)
                    search_pats.addAll(trie.getForms(lems[i]));
            }
        }

        if (trie.findLemma(pattern.toLowerCase()))
            search_pats.addAll(trie.getForms(pattern.toLowerCase()));
        search_pats.add(pattern);

        Set<String> search_set = new HashSet<>(search_pats);

        // Регулярное выражение для поиска всевозможных словоформ в тексте
        String regExp = "(?<![Ёёа-яА-Яa-zA-Z0-9])(?:";

        for (String pat : search_set) {
            regExp += pat + "|";
        }
        regExp = regExp.substring(0, regExp.length() - 1);
        regExp += ")(?![Ёёа-яА-Яa-zA-Z0-9])";

        //System.out.println(regExp);
        return regExp;
    }

    private int lineLengthClean(String line) {
        String utfSymb = "\\\\[u][0-9A-F]{4}";
        return line.replaceAll(utfSymb, "_").replaceAll("\\\\", "").length();
    }

    // Обработка файла морфоанализатором mystem - запись словоформ в префиксное дерево и лемм - в хэш-таблицу
    private void launchParser(String filename) {
        if (filename.equals(""))
            return;
        String line;
        Process p = null;
        BufferedReader is = null;

        try {
            p = Runtime.getRuntime().exec(new String[]{"mystem.exe", "-e", "UTF-8", "-cni", filename});
            is = new BufferedReader(new InputStreamReader(p != null ? p.getInputStream() : null));
            trie = new Trie();
            int cur_pos = 0;
            while ((line = is.readLine()) != null) {
                java.util.List<String> words = wordMatches(line);
                //System.out.println("Current position: " + cur_pos); // Для отладки
                if (words != null) {
                    trie.put(cur_pos + "_" + words.get(0), words.subList(1, words.size()));
                    cur_pos += line.indexOf("{");
                } else {
                    cur_pos += lineLengthClean(line);
                }
                //System.out.println(line); // Для отладки

            }
            //System.out.println("Анализ файла с помощью mystem завершен!");
        } catch (IOException e) {
            System.out.println("Error while launching mystem: " + e.getMessage());
        } finally {
            if (is != null)
                try {
                    is.close();
                } catch (IOException e) {
                    System.out.println("Error while closing reader from mystem process: " + e.getMessage());
                }
            if (p != null)
                try {
                    p.getInputStream().close();
                    p.getOutputStream().close();
                    p.getErrorStream().close();
                } catch (IOException e) {
                    System.out.println("Error while closing mystem process: " + e.getMessage());
                }
        }

    }

    // Удаление подсветки с TextArea
    private void removeDefaultHighlighter(JTextArea txtarea) {
        Highlighter highlighter = txtarea.getHighlighter();
        highlighter.removeAllHighlights();
        curhl = null;
    }

    private void execRegBatch(JTextArea txtarea, String pattern) {
        String pattern_unedited = jtxtuser.getText();
        removeDefaultHighlighter(txtarea);       // Очищаем предыдущую подсветку
        listModel.clear();

        if (txtarea.getText().isEmpty() || pattern.equals("") || trie == null)
            return;

        RegClass myReg = new RegClass(pattern);
        LinkedList<MatchEntry> match_list = myReg.getMatches(txtarea.getText());

        if (match_list == null)
            return;

        MatchEntry pair;
        int cur_end = 0;
        int modeflag = 2;

        java.util.List<ArrayList<String>> listData = new ArrayList<>();
        ArrayList<WordAttrs> attrs_info = new ArrayList<>();
        HashSet<String> attrs_set = new HashSet<>();
        if (isRegMode) {
            attrs_set.add("");
            modeflag = 1;
        }

        while (!match_list.isEmpty()) {
            try {

                pair = match_list.pollFirst();
                listModel.addElement(pair);

                String cur_word = pair.getEntry();
                int cur_start = pair.getBeg();

                if (isRegMode) {
                    attrs_info.add(new WordAttrs(cur_word, "", cur_start));
                    //System.out.println("[REGMODE] ADDING TO attrs_info " + cur_word + ", " + cur_start);
                } else
                    for (String attr : trie.getWFormAttrsByPos(cur_word, cur_start)) {
                        attrs_set.add(attr);
                        //System.out.println("ADDING TO attrs_info " + cur_word + ", " + cur_start + ", " + attr);
                        attrs_info.add(new WordAttrs(cur_word, attr, cur_start));
                    }

                ArrayList<String> listElData = new ArrayList<>();
                listElData.add(String.valueOf(cur_start));
                listElData.add(String.valueOf(pair.getEnd()));
                listElData.add(cur_word);
                listElData.add(pattern_unedited);
                listElData.add(String.valueOf(modeflag));

                listData.add(listElData);

                if (pair.getBeg() >= cur_end)
                    highlighter.addHighlight(pair.getBeg(), pair.getEnd(), painter);
                if (pair.getBeg() < cur_end && pair.getEnd() > cur_end) {
                    highlighter.addHighlight(cur_end, pair.getEnd(), painter);
                }
                cur_end = pair.getEnd();

            } catch (BadLocationException e) {
                JOptionPane.showMessageDialog(jfrm, e);
            }
        }

        db.insertAttrs(attrs_set, isRegMode);
        long time_start = System.currentTimeMillis();
        //System.out.println("Started: "+ time_start);

        if (listData.size() > MaxEntryNumber) {
            int j = 0;
            java.util.List<ArrayList<String>> listDataSmall;
            for (int i = 1; i <= listData.size() / MaxEntryNumber; i++) {
                listDataSmall = listData.subList(j, i * MaxEntryNumber);
                db.insertDataBatch(listDataSmall, filename);
                j = i * MaxEntryNumber;
            }
            listDataSmall = listData.subList(j, listData.size());
            db.insertDataBatch(listDataSmall, filename);

        } else
            db.insertDataBatch(listData, filename);

        db.createRefs(attrs_info, isRegMode);
        annTableModel.setData(db.showAnnot());
        long time_end = System.currentTimeMillis();
        //System.out.println("Finished: "+ time_end);
        long time = time_end - time_start;
        System.out.println("Time spent on inserting word " + jtxtuser.getText() + ": " + time);
    }

    // Поиск регулярного выражения
    private void execReg(JTextArea txtarea, String pattern) {

        String pattern_unedited = jtxtuser.getText();
        removeDefaultHighlighter(txtarea);       // Очищаем предыдущую подсветку
        listModel.clear();

        if (txtarea.getText().isEmpty() || pattern.equals("") || trie == null)
            return;

        RegClass myReg = new RegClass(pattern);
        LinkedList<MatchEntry> match_list = myReg.getMatches(txtarea.getText());

        if (match_list == null)
            return;

        MatchEntry pair;
        int cur_end = 0;
        int modeflag = 2;

        java.util.List<String> listData = new ArrayList<>();
        ArrayList<WordAttrs> attrs_info = new ArrayList<>();
        HashSet<String> attrs_set = new HashSet<>();
        if (isRegMode) {
            attrs_set.add("");
            modeflag = 1;
        }

        while (!match_list.isEmpty()) {
            try {
                pair = match_list.pollFirst();
                listModel.addElement(pair);

                String cur_word = pair.getEntry();
                int cur_start = pair.getBeg();

                if (isRegMode) {
                    attrs_info.add(new WordAttrs(cur_word, "", cur_start));
                    //System.out.println("[REGMODE] ADDING TO attrs_info " + cur_word + ", " + cur_start);
                } else
                    for (String attr : trie.getWFormAttrsByPos(cur_word, cur_start)) {
                        attrs_set.add(attr);
                        //System.out.println("ADDING TO attrs_info " + cur_word + ", " + cur_start + ", " + attr);
                        attrs_info.add(new WordAttrs(cur_word, attr, cur_start));
                    }

                listData.add(pair.getBeg() + ", " + pair.getEnd() + ", '" + pair.getEntry() + "', '" + pattern_unedited + "', " + modeflag);

                if (pair.getBeg() >= cur_end)
                    highlighter.addHighlight(pair.getBeg(), pair.getEnd(), painter);
                if (pair.getBeg() < cur_end && pair.getEnd() > cur_end) {
                    highlighter.addHighlight(cur_end, pair.getEnd(), painter);
                }
                cur_end = pair.getEnd();

            } catch (BadLocationException e) {
                System.out.println(e);
            }
        }

        db.insertAttrs(attrs_set, isRegMode);

        long time_start = System.currentTimeMillis();
        //System.out.println("Started: "+ time_start);

        if (listData.size() > MaxEntryNumber) {
            int j = 0;
            java.util.List<String> listDataSmall;
            for (int i = 1; i <= listData.size() / MaxEntryNumber; i++) {
                listDataSmall = listData.subList(j, i * MaxEntryNumber);

                db.insertData(listDataSmall, filename);
                j = i * MaxEntryNumber;
            }
            listDataSmall = listData.subList(j, listData.size());

            db.insertData(listDataSmall, filename);
        } else
            db.insertData(listData, filename);

        db.createRefs(attrs_info, isRegMode);
        annTableModel.setData(db.showAnnot());
        long time_end = System.currentTimeMillis();
        //System.out.println("Finished: "+ time_end);
        long time = time_end - time_start;
        System.out.println("Time spent on inserting word " + jtxtuser.getText() + ": " + time);
    }

    // Экспорт размеченного текста в XML
    public String writeXML(JTextArea txtarea, DefaultListModel<MatchEntry> listModel) {
        String res = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><text>";
        String text = txtarea.getText();

        LinkedList<IntervalBorder> borderList = new LinkedList<>();

        for (int i = 0; i < listModel.size(); i++) {
            borderList.add(new IntervalBorder(listModel.get(i).getBeg(), true, i));
            borderList.add(new IntervalBorder(listModel.get(i).getEnd(), false, i));
        }

        Collections.sort(borderList);

        if (listModel.isEmpty()) {
            return res + text + "</text>";
        }

        if (listModel.size() == 1) {
            int cur_beg = listModel.get(0).getBeg();
            int cur_end = listModel.get(0).getEnd();
            return res + text.substring(0, cur_beg) + "<match>" + text.substring(cur_beg, cur_end) + "</match>" + text.substring(cur_end) + "</text>";
        }

        int tpos = 0;

        while (!borderList.isEmpty()) {
            IntervalBorder brd = borderList.pollFirst();
            res += text.substring(tpos, brd.getPos()) + "<match id='" + brd.getPairID() + "' pos=";
            if (brd.isLeft())
                res += "'start'/>";
            else
                res += "'end'/>";
            tpos = brd.getPos();
        }

        res += text.substring(tpos) + "</text>";
        return res;
    }

    public void saveFile(JTextArea txtarea) {
        if (txtarea.getText().isEmpty()) {
            JOptionPane.showMessageDialog(jfrm, "Попытка сохранить пустой файл.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return (f.getName().toLowerCase().endsWith(".xml") || f.isDirectory());
            }

            @Override
            public String getDescription() {
                return ".xml";
            }
        });
        chooser.setMultiSelectionEnabled(false);
        try {
            chooser.setCurrentDirectory(new File(getProjectRoot()));
        } catch (URISyntaxException | IOException e) {
            System.out.println(e);
        }
        int option = chooser.showSaveDialog(jfrm);
        if (option != JFileChooser.APPROVE_OPTION)
            return;
        File sf = chooser.getSelectedFile();

        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sf.getPath()), "UTF-8"))) {

            writer.write(writeXML(txtarea, listModel));
        } catch (IOException e) {
            JOptionPane.showMessageDialog(jfrm, e, "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
    }

    public void openFile() {
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return (f.getName().toLowerCase().endsWith(".txt") || f.isDirectory());
            }

            @Override
            public String getDescription() {
                return ".txt";
            }
        });
        chooser.setMultiSelectionEnabled(false);
        try {
            chooser.setCurrentDirectory(new File(getProjectRoot()));
        } catch (URISyntaxException | IOException e) {
            System.out.println(e);
        }
        int option = chooser.showOpenDialog(jfrm);
        if (option != JFileChooser.APPROVE_OPTION)
            return;
        File sf = chooser.getSelectedFile();
        filename = sf.getAbsolutePath();
        launchParser(filename);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"))) {
            StringBuilder buffer = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
                buffer.append("\n");
            }
            jtxt.setText(buffer.toString());
        } catch (IOException e) {
            JOptionPane.showMessageDialog(jfrm, e);
        }
    }

    public void createFileMenu() {
        JMenuItem item;

        fileMenu = new JMenu("Файл");

        item = new JMenuItem("Очистить");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                jtxt.setText("");
                jtxtuser.setText("");
                listModel.clear();
                highlighter.removeAllHighlights();
                curhl = null;
                trie = null;
            }
        });

        fileMenu.add(item);

        item = new JMenuItem("Открыть...");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                openFile();
            }

        });

        fileMenu.add(item);

        item = new JMenuItem("Сохранить");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                saveFile(jtxt);
            }
        });
        fileMenu.add(item);

        item = new JMenuItem("Выйти");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                db.disconnect();
                jfrm.dispose();
                System.exit(0);
            }
        });

        fileMenu.add(item);
    }

    public void createDBMenu() {
        dbMenu = new JMenu("База аннотаций");
        JMenuItem item = new JMenuItem("Показать");
        item.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dbWin.toFront();
                dbWin.setVisible(true);
            }
        });
        dbMenu.add(item);
    }

    public void createHelpMenu() {
        JMenuItem item;
        helpMenu = new JMenu("Помощь");
        item = new JMenuItem("О программе");
        item.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(jfrm, "Поиск словоформ, а также нахождение соответствия регулярному выражению в тексте.\n\nПроноза Екатерина\nСПбГУ\n2012", "О программе", JOptionPane.PLAIN_MESSAGE);
            }
        });
        helpMenu.add(item);
        item = new JMenuItem("Справка");
        item.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(jfrm, "Программа работает в двух режимах: в режиме\nпоиска соответствия регулярному выражению, \nа также в режиме поиска всех возможных словоформ,\nотносящихся к введенному слову.", "Справка", JOptionPane.PLAIN_MESSAGE);
            }
        });
        helpMenu.add(item);
    }

    public void createOptionsMenu() {
        JMenuItem item;
        optMenu = new JMenu("Настройки БД");
        String name = "Изменить способ вставки данных";
        item = new JMenuItem(name);
        item.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                batchInsertMode = !batchInsertMode;
                if (batchInsertMode) {
                    dbModeLabel.setText("БД: вставка batch");
                    System.out.println("Batch mode");
                } else {
                    dbModeLabel.setText("БД: вставка конкатенацией");
                    System.out.println("Concatenation mode");
                }
            }
        });
        optMenu.add(item);
    }

    public String getProjectRoot() throws URISyntaxException, java.io.IOException {
        URL u = this.getClass().getProtectionDomain().getCodeSource().getLocation();
        File f = new File(u.toURI());
        return f.getParentFile().getParentFile().getParent();
    }
}
